package com.gengzp.common.exception.processor;

import com.gengzp.common.exception.BusinessException;
import com.gengzp.common.model.generic.resp.Result;
import com.gengzp.permission.exception.PermissionException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.stream.Collectors;

import static com.gengzp.common.constants.ExceptionCodeConstants.PARAM_ILLEGAL_ERROR;
import static com.gengzp.common.constants.HttpStatusCodeConstants.PARAM_VALIDATION_FAIL;
import static com.gengzp.common.constants.HttpStatusCodeConstants.PERMISSION_DENIED;

/**
 * @ClassName GlobalExceptionProcessor
 * @Description 全局异常处理器
 * @Author gengzp
 * @Date 2025/9/8 14:18
 */
@ControllerAdvice
public class GlobalExceptionProcessor {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionProcessor.class);

    /**
     * 处理其他不可控异常（处理其他的 Exception）
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.OK)  // 前端返回200, 为了前端能够读取返回的错误信息
    public Result<Void> handleException(Exception e) {
        logger.error("出现系统异常，详细信息: ", e);  // 打印完整堆栈，便于排查

        // 递归获取最底层的异常原因（避免多层包装导致信息丢失）
        Throwable rootCause = getRootCause(e);

        // 提取错误信息（优先用最底层异常的message，避免null）
        String errorMessage = rootCause.getMessage();
        if (StringUtils.isBlank(errorMessage)) {
            errorMessage = "系统异常，请联系管理员";  // 兜底默认信息
        }

        return Result.getFailResult(errorMessage);
    }

    /**
     * 处理自定义业务异常（处理手动抛出 BusinessException）
     */
    @ResponseBody
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.OK) // 前端返回200, 为了前端能够读取返回的错误信息
    public Result<Void> handleBusinessException(BusinessException e) {
        logger.error("出现自定义业务异常: {}", e.getMessage());
        return convertExceptionInfo2Result(e.getCode(), e.getMessage());
    }

    /**
     * 处理参数校验异常（处理 @Valid 注解参数校验不通过）
     */
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.OK) // 前端返回200, 为了前端能够读取返回的错误信息
    public Result<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        String errorMessage = e.getBindingResult().getFieldErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining(";\n"));
        logger.error("出现参数校验异常: {}", errorMessage);
        return convertExceptionInfo2Result(PARAM_ILLEGAL_ERROR, errorMessage);
    }

    /**
     * 处理权限框架的权限认证异常
     */
    @ResponseBody
    @ExceptionHandler(PermissionException.class)
    @ResponseStatus(HttpStatus.OK) // 前端返回200, 为了前端能够读取返回的错误信息
    public Result<Void> handlePermissionException(PermissionException e) {
        logger.error("出现权限校验异常: {}", e.getMessage());
        return Result.getFailResult(PERMISSION_DENIED, "权限校验不通过, " + e.getMessage());
    }

    private Result<Void> convertExceptionInfo2Result(int code, String errorMessage) {
        // 普通业务异常 (1000-1999)
        if (code < 2000) {
            errorMessage = "操作失败, " + errorMessage;
        }
        // 参数校验异常 (2000-2999)
        else if (code < 3000) {
            errorMessage = "参数校验不通过, " + errorMessage;
        }
        return Result.getFailResult(PARAM_VALIDATION_FAIL, errorMessage);
    }

    /**
     * 递归获取最底层的异常原因
     */
    private Throwable getRootCause(Throwable e) {
        Throwable cause = e.getCause();
        if (cause != null && cause != e) {
            return getRootCause(cause);
        }
        return e;  // 没有更深层的cause，返回当前异常
    }

}
